﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Game
{

    class Scheduler_AStar  // 預計MA 目前是GA
    {

        Player _P1, _P2;

        Random _rand = new Random();
        List<ACTION_MODE> _actionlist;
        Map _tempMap;
        Map _Now;
        UI _data;
        List<int> _order;
        List<int> _Bestorder;
        int _nowDamage;
        int _BestDamage;
        int _count;
        int _side;
        int _OrderSize;
        const int MAX_COUNT = 2000;

        public List<int> Order {
            get { return _Bestorder; }
        }
        public Scheduler_AStar(UI data, int side,List<ACTION_MODE> actionList)
        {
            _actionlist = actionList;
            _side = side;
            _data = data;
            _OrderSize = data.GetPlayer(_side).Slimes.Count;
            _Now = data.Map;
            _order = new List<int>(_OrderSize);
            _Bestorder = new List<int>(_OrderSize);
            
            _nowDamage = 0;
            _BestDamage = -1;
            _count = 0;
        }

       
        public void Run()
        {
            testcount = _OrderSize;
            Search(_OrderSize, _data);             
        }


        int testcount = 0;
        bool Search(int depth,UI data) {
            if (End())
            {
                return false;
            }
            if (depth <= 0 )
            {
                CheckBestOrder();
                return true;
            }
            List<Position> DamageList = new List<Position>();
            Map tempmap = data.Map;
            H(ref DamageList, data);
            for (int i = 0; i < DamageList.Count; i++)
            {
                if (DamageList[i].Y == -1)
                {
                    return false;
                }
                if ((DamageList[i].Y == 0 && _Bestorder.Count != 0)) {
                    CheckBestOrder();
                    return false;
                }
               
                SlimeGame temp = new SlimeGame(data.GameData);
                UI tempui = temp.GetUI();
                Slime S = tempui.GetPlayer(_side).Slimes[DamageList[i].X];
                DoAction(DamageList[i], S, tempui);
                Search(depth - 1, tempui);
                UndoAction(DamageList[i]);
            }
            return true;
        }
        int MaxDamage = 0;
        int NextDamage = 0;
        void H(ref List<Position>  DamageList,UI data)
        {

            for (int i = 0; i < data.GetPlayer(_side).Slimes.Count; i++)
            {
                SlimeGame sg = new SlimeGame(data.GameData);
                UI tempdata = sg.GetUI();
                List<Slime> list = tempdata.GetPlayer(_side).Slimes;
                Slime S = list[i];
                if (!S.Active || !S.CanMove)
                {
                    DamageList.Add(new Position(i, -1));
                    continue;
                }
                int sum1 = 0;
                int sum2 = 0;
                for (int j = 0; j < tempdata.GetPlayer(_side ^ 1).Slimes.Count; j++)
                {
                    sum1 += tempdata.GetPlayer(_side ^ 1).Slimes[j].HP;
                }
                ActionSet.DoAction(S, tempdata, _actionlist[i], _side, false);
                for (int j = 0; j < tempdata.GetPlayer(_side ^ 1).Slimes.Count; j++)
                {
                    sum2 += tempdata.GetPlayer(_side ^ 1).Slimes[j].HP;
                }
                int damage = sum1 - sum2;
                
                DamageList.Add(new Position(i, damage));
               
            }
            DamageList.Sort((a, b) => { return (-a.Y.CompareTo(b.Y)); });
        }
        void DoAction(Position data,Slime S,UI gamedata) {
            int sum1 = 0;
            int sum2 = 0;
            for (int i = 0; i < gamedata.GetPlayer(_side^1).Slimes.Count; i++)
            {
                sum1 += gamedata.GetPlayer(_side ^ 1).Slimes[i].HP;
            }
            ActionSet.DoAction(S, gamedata, _actionlist[data.X], _side,false);
            for (int i = 0; i < gamedata.GetPlayer(_side ^ 1).Slimes.Count; i++)
            {
                sum2 += gamedata.GetPlayer(_side ^ 1).Slimes[i].HP;
            }
            _order.Add(data.X);
            _nowDamage += sum1 - sum2;
            if (_nowDamage > MaxDamage) {
                MaxDamage = _nowDamage;
            }
        }
        void UndoAction(Position data)
        {
            _order.RemoveAt(_order.Count-1);
            _nowDamage -= data.Y;
        }
        void CheckBestOrder() {            
            if (_nowDamage <= _BestDamage) { return; }            
            _Bestorder.Clear();
            _BestDamage = _nowDamage;
            for (int i = 0; i < _order.Count; i++)
            {
                _Bestorder.Add(_order[i]);
            }
            if (_Bestorder.Count < _OrderSize)
            {
                int[] countArray = new int[_OrderSize];
                for (int i = 0; i < _Bestorder.Count; i++)
                {
                    countArray[_Bestorder[i]] = 1;
                }
                for (int i = 0; i < _OrderSize; i++)
                {
                    if (countArray[i] == 0)
                    {
                        _Bestorder.Add(i);
                    }
                }
            }
        }
        bool End()
        {
            ++_count;
            if (_count >= MAX_COUNT)
            {
                return true;
            }
            else {
                return false;
            }
        }
    }
}

